#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "digimon.h"
#include "bmp.h"
#include "digimon_libs.h"
#include "digimon_api.h"

#include <pthread.h>
/*****api*****/
uchar digimon_bmps[12][DIGIMON_W][DIGIMON_H] = {0}; /* digimon_bmps */
pthread_t pt_digimon_time;
pthread_t pt_digimon_live;
int digimon_evolution_time[] = {
    EGG_TIME, YOUZHIQI_TIME, YOUNIANQI_TIME, CHENGZHANGQI_TIME, 
    CHENGSHUQI_TIME, WANQUANTI_TIME, JIUJITI_TIME
};

digimon_t *digimon_create(uint8_t digiType, digimon_t **digi);
DIGI_VOID digimon_alive(digimon_t *digi);
DIGI_VOID digimon_display(digimon_t *digi, uint8_t m_tiki);
DIGI_VOID digimon_dis_menu(uint8_t index);
DIGI_VOID digimon_dump(digimon_t *digi);


static void digimon_rander_event(struct digimon_st *digimon);
static void digimon_status(struct digimon_st *digimon);
static void digimon_evolution(struct digimon_st *digimon);

digimon_api digi_api = {
    .digimon_create = digimon_create,
    .digimon_alive = digimon_alive,
    .digimon_display = digimon_display,
    //.digimon_menu = digimon_dis_menu,
    .digimon_dump = digimon_dump,
};

void *digimon_time_pt(void *arg)
{
    struct digimon_st *digimon = (struct digimon_st *)arg;
    while(1)
    {
        digimon->digi_time++;
        //sleep(1);
        delay_ms(500);
    }
    return NULL;
}

void *digimon_alive_pt(void *arg)
{
    struct digimon_st *digimon = (struct digimon_st *)arg;
    uint8_t itiki = 0;
    while(1)
    {
        itiki++;
        if(itiki > 30)
            itiki = 0;

        if(itiki == 60 && !status_cek_flag(digimon->digi_status, STA_SLEEP))
        {
            digimon_rander_event(digimon);
        }
        digimon_status(digimon);
        digimon_evolution(digimon);
        sleep(1);
    }
    
    return NULL;
}

DIGI_VOID digimon_alive(digimon_t *digi)
{
    pthread_create(&pt_digimon_time, NULL, &digimon_time_pt, digi);
    pthread_create(&pt_digimon_live, NULL, &digimon_alive_pt, digi);
}


/*********************************************************************
 *  ���ƣ� digimon_create
 *  ���ܣ� ���뱦����ʼ��
 *  ������ uint8_t digiType
 *  ����ֵ��digimon_t * �ṹ��ָ��
 ********************************************************************/
digimon_t *digimon_create(uint8_t digiType, digimon_t **digi)
{
    struct digimon_st *digimon = NULL;
    digimon = (struct digimon_st *)malloc(sizeof(struct digimon_st));
    *digi = digimon;
    
    strcpy(digimon->digi_name, digimon_libs[digiType].digi_name);
    digimon->digi_type = digimon_libs[digiType].digi_type;

    digimon->digi_level = DIGI_EGG;
    digimon->digi_age = 0;
    digimon->digi_weight = 5;
    digimon->digi_hungry = 100;
    digimon->digi_strength = 4;
    digimon->digi_dp = 20;
    digimon->digi_maxdp = 20;
    digimon->digi_enableB = 0;
    digimon->digi_enableJ = 0;
    digimon->digi_evolution = 0;
    digimon->digi_max_evolution = digimon_evolution_time[digimon->digi_level];
    digimon->digi_currency = 300;
    digimon->digi_health = 100;

    digimon->digi_win = 0;
    digimon->digi_battle = 0;
    digimon->digi_attck = 0;
    digimon->digi_defence = 0;
    digimon->digi_miss = 0;

    digimon->digi_time = 0;
    digimon->digi_status = 0;
    digimon->digi_dabian = 0;
    digimon->digi_status = STA_NORMAL;
    digimon->digi_misscall = 0;
    digimon->bmp = digimon_bmps;
    //digimon->skill_bmp = digimon_001_Bubbmon_skill;

    digimon->digi_battle = 0;
    //sprintf(digimon.digi_type, "%s", "Fr");
    init_digimon_bmps(digimon_libs[digiType].digi_id,digimon_libs[digiType].bmp_num, digimon_bmps);


    //digimon_timer_init();
    /* ����digimon�����߳� */
    //xTaskCreate(digi_alive, "digimon alive", 512, NULL, 2, NULL);
    
    return (digimon_t *)digimon;
}

void digimon_dump(digimon_t *digi)
{
    struct digimon_st *digimon = digi;
    printf("\n----------digimon info------------\n");
    printf("digimon ID:%d\n",digimon->digi_id);
    printf("digimon name:%s\n",digimon->digi_name);
    printf("digimon time:%d\n",digimon->digi_time);
    printf("digimon level:%d\n",digimon->digi_level);
    printf("digimon hungry:%d\n",digimon->digi_hungry);
    printf("digimon strength:%d\n",digimon->digi_strength);
    printf("digimon dp:%d\n",digimon->digi_dp);
    printf("digimon evolution:%d / %d (%d%%)\n",digimon->digi_evolution, digimon->digi_max_evolution,(digimon->digi_evolution*100/digimon->digi_max_evolution));
    printf("digimon health:%d\n",digimon->digi_health);
    printf("digimon misscall:%d\n",digimon->digi_misscall);
    printf("digimon dabian:%d\n",digimon->digi_dabian);

    printf("status:\n");
   
    if(status_cek_flag(digimon->digi_status,STA_HUNGRY))
         printf("hungry ");
    if(status_cek_flag(digimon->digi_status,STA_SHIRT))
        printf("dabian ");
    if(status_cek_flag(digimon->digi_status,STA_ILL))
        printf("ill ");
    if(status_cek_flag(digimon->digi_status,STA_SLEEP))
        printf("sleep ");        

    printf("\n----------------------------------\n");
}


static void digimon_rander_event(struct digimon_st *digimon)
{
    uint8_t proability = 0;
    uint8_t dabian_proability = 0;
    uint8_t ill_probability = 0;
    static uint8_t old_proability = 0;
    

    if(old_proability ==1 )
    {
        proability = random_event(digimon->digi_time, 5, 10); //50%
    }else{
        proability = 1;
    }
    old_proability = proability;

    if(proability == 1)
    {
        digimon->digi_hungry--;
        if(digimon->digi_hungry <= 0)
        {
            digimon->digi_hungry = 0;
        }       
    }

    /* 大便 20%*/
    if(!status_cek_flag(digimon->digi_status, STA_SHIRT))
    {
        dabian_proability = random_event(digimon->digi_time, 2, 10);
        if(dabian_proability == 1)
        {
            /* 随机获得0-3的大便 */
            digimon->digi_dabian = get_random(digimon->digi_time, 0, 3);
        }
    }
    
    /* 生病 5%*/
    if(!status_cek_flag(digimon->digi_status,STA_ILL))
    {
        ill_probability = random_event(digimon->digi_time,5, 100);
        if(ill_probability == 1)
        {
            digimon->digi_health = 50;
        }
    }
}

static void digimon_hungry_check(struct digimon_st *digimon)
{
    if(digimon->digi_hungry <= 0)
    {
        status_set_falg(digimon->digi_status, STA_HUNGRY);
    }else{
        status_del_flag(digimon->digi_status, STA_HUNGRY);
    }
}

static void digimon_clean_check(struct digimon_st *digimon)
{
    if(digimon->digi_dabian > 0)
    {
        status_set_falg(digimon->digi_status, STA_SHIRT);
    }else{
        status_del_flag(digimon->digi_status, STA_SHIRT);
    }
}

static uint8_t digimon_health_check(struct digimon_st *digimon)
{
    /* 健康度 0 - 100 */
    /* 每1min检查一次 */
    /* 健康度归零 死亡 */
    /* 如果大便就扣健康度 */
    /* 如果受伤就扣健康度 */
    /* 如果一直肚子饿也扣健康度 */
    /* 如果健康度小于50就生病 */
    /* 如果生病了，就不能进化 */
    /* 如果生病了，8小时后会死亡 */
    static int icnt = 0;
    uint8_t imin = 0;
    /* 如果睡眠，不进行健康检查 */
    if(status_cek_flag(digimon->digi_status, STA_SLEEP))
    {
        return 0;
    }
    icnt++;
    imin = icnt % 60;
    if(digimon->digi_health >= 50)
    {
        if(imin == 0)
        {
            digimon->digi_health -= digimon->digi_dabian;
            if(digimon->digi_hungry <= 10)
            {
                digimon->digi_health--;
            }
            if(status_cek_flag(digimon->digi_status, STA_HURT))
            {
                digimon->digi_health--;
            }
        }
    }else{
        status_set_falg(digimon->digi_status, STA_ILL);
        imin = icnt % (60*10); //10min
        if(imin == 0)
        {
            digimon->digi_health --;
            icnt = 0;
        }
    }

    if(digimon->digi_health <= 0)
    {
        //die
        return -1;
    }
    return 0;
}

/*********************************************************************
 *  名称： digi_misscall_check
 *  功能： misscall 统计
 *  参数： struct digimon_st *digimon
 *  返回值：1 异常 0 健康
 ********************************************************************/
static void digimon_misscal_check(struct digimon_st *digimon)
{
    /* 用于记录异常状态的时间，如果时间到达10分钟，便产生以此misscall */
    /* 饥饿，睡觉唤醒，睡觉没有关灯 算是misscall，拉大便，生病，受伤不算misscall */
    static uint8_t time_count = 0;
    static uint16_t i_misscall_count = 0;

    /* 1min检查一次 */
    time_count++;
    if(time_count >= 60)
    {
        /* 如果检查到饥饿 */
        if(status_cek_flag(digimon->digi_status, STA_HUNGRY))
        {
            i_misscall_count++;
            if(i_misscall_count >= 10)
            {
                printf("hungry misscall ++, now: %d\n",digimon->digi_misscall);
                digimon->digi_misscall++;
                i_misscall_count = 0;
            }
            time_count = 0;
            return;
        }

        /* 如果睡眠没有关灯*/

    }
}

/*********************************************************************
 *  名称： digimon_status
 *  功能： digimon 状态
 *  参数： digimon_t * 结构体指针
 *  返回值：void
 ********************************************************************/
static void digimon_status(struct digimon_st *digimon)
{
    digimon_hungry_check(digimon);
    digimon_clean_check(digimon);
    digimon_health_check(digimon);
    digimon_misscal_check(digimon);
}
static void digomon_evolution_egg(struct digimon_st *digimon, int *start_time)
{
    if(digimon->digi_time > digimon_evolution_time[digimon->digi_level])
    {
        printf("==================EGG\n");
        //digimon_incubate(digimon);
        digimon->digi_level = DIGI_YOUZHIQI;
        digimon->digi_max_evolution = digimon_evolution_time[DIGI_YOUZHIQI];
        *start_time = digimon->digi_time;
    }
}

static uint8_t digimon_evolution_select(struct digimon_st *digimon)
{
    uint8_t evol_select = 99;
    switch (digimon->digi_level)
    {
    case DIGI_YOUZHIQI:
        evol_select = 0;
    break;
    case DIGI_YOUNIANQI:
        if(digimon->digi_misscall == 0)
        {
            evol_select = 0;
        }else if(digimon->digi_misscall <= 2)
        {
            //1-2 times misscal
            evol_select = 1;
        }else{
            //3 times more
            evol_select = 2;
        }
    break;
    
    case DIGI_CHENGZHANGQI:
        if(digimon->digi_misscall <= digimon_libs[digimon->digi_id].digi_evol_sution[0][0])
        {
            if(digimon->digi_strength >= digimon_libs[digimon->digi_id].digi_evol_sution[0][1])
            {
                evol_select =  0;
            }else{
                evol_select = 1;
            }
        }else{
            if(digimon->digi_strength >= digimon_libs[digimon->digi_id].digi_evol_sution[2][1])
            {
                evol_select = 2;
            }else{
                evol_select = 3;
            }
        }
    break;
    case DIGI_CHENGSHUQI:
    case DIGI_WANQUANTI:
        if(digimon->digi_misscall <= digimon_libs[digimon->digi_id].digi_evol_sution[0][0])
        {
            evol_select = 0;
        }
    break;
    default:
        break;
    }
    return evol_select;
}

static void digimon_evolution_handl(struct digimon_st *digimon, int *start_time)
{
    uint8_t evolution_idx = 0; //进化分支 0-3
    if((digimon->digi_time - *start_time) > digimon_evolution_time[digimon->digi_level])
    {
        evolution_idx = digimon_evolution_select(digimon);
        printf("==== digimonid:%d\n", digimon->digi_id);
        printf("==== evol:%d\n", evolution_idx);
        digimon->digi_id = digimon_libs[digimon->digi_id].digi_evol[evolution_idx];
        printf("==== new id:%d\n", digimon->digi_id);
        strncpy(digimon->digi_name, digimon_libs[digimon->digi_id].digi_name, 20);
        digimon->digi_type = digimon_libs[digimon->digi_id].digi_type;
        init_digimon_bmps(digimon->digi_id,digimon_libs[digimon->digi_id].bmp_num, digimon_bmps);
        printf("====digimon level%d\n",digimon->digi_level);
        digimon->digi_level += 1;
        printf("====after digimon level%d\n",digimon->digi_level);
        digimon->digi_max_evolution = digimon_evolution_time[digimon->digi_level];
        digimon->digi_misscall = 0;
        *start_time = digimon->digi_time;
    }
}

static void digimon_evolution(struct digimon_st *digimon)
{
    static int start_time = 0;
    /* 如果生病或者睡觉，就停止进化 */
    if(status_cek_flag(digimon->digi_status, STA_ILL) || status_cek_flag(digimon->digi_status, STA_SLEEP))
    {
        return;
    }
    if(digimon->digi_level >= DIGI_JIUJITI)
    {
        return;
    }
    switch(digimon->digi_level)
    {
        case DIGI_EGG:
            digomon_evolution_egg(digimon, &start_time);   
        break;
        case DIGI_YOUZHIQI:
        case DIGI_YOUNIANQI:
        case DIGI_CHENGZHANGQI:
        case DIGI_CHENGSHUQI:
        case DIGI_WANQUANTI:
        case DIGI_JIUJITI:
        case DIGI_CHAOJIUJITI:
        digimon_evolution_handl(digimon, &start_time);
        break;
    }
    digimon->digi_evolution = digimon->digi_time - start_time;
}